#pragma once

namespace Melting
{

	template< class ErrorPolicy > class BaseFile;

	/// 
	class DefaultErrorPolicy
	{
	public:
		static bool OnError( BaseFile< DefaultErrorPolicy > & _rFile, const char* _strFilepath )
		{
			// fixme with FLOAT code!
			char astrErrorMessage[128];
			
			LOG( astrErrorMessage, "File not found : %s\n", _strFilepath );
			MB_ERROR( false, astrErrorMessage );

			return false;
		}
	};
	
	/// 
	class WarningPolicy
	{
	public:
		static bool OnError( BaseFile< WarningPolicy > & _rFile, const char* _strFilepath )
		{
			// fixme with FLOAT code!
			char astrErrorMessage[128];
			
			LOG( "File not found : %s\n", _strFilepath );
//			LOG( astrErrorMessage, "File not found : %s\n", _strFilepath );

			return false;
		}
	};

	enum FileSeekMode
	{
		MB_SEEK_SET = FILE_BEGIN
	,	MB_SEEK_CUR = FILE_CURRENT
	,	MB_SEEK_END = FILE_END
	};
	
	class DefaultErrorPolicy;

	typedef SYSTEMTIME SystemTime;

	/// class file is an abstraction of DS file
	/// special error behaviour can be applied through policy which is, by default a policy which prints a message 
	/// on screen and stops console
	/// to set a special behaviour, just create a policy with a function OnError( const char* _strFilepath )
	template< class ErrorPolicy = DefaultErrorPolicy >
	class BaseFile
	{
	public:
		/// default constructor
		BaseFile( void );

		/// constructor with a file name
		BaseFile( const char* _strFilepath, bool _bWrite = false, const char* _strLog = nullptr );

		/// destructor
		~BaseFile( void );

		/// Open a file
		bool											Open( const char* _strFilepath, bool _bWrite = false, const char* _strLog = nullptr );
		/// Is this file open ?
		bool											IsOpen( void ) const { return mbIsOpen;}
		/// Close file
		void											Close( void );

		/// Get file length (in bytes)
		ULONG											GetLength( void );


		/// Read data
		template<class T>
		long											Read( T& _rtOutValue );
/*		
		long											Read( UBYTE& ubToRead );
		long											Read( SBYTE& sbToRead );
		long											Read( UWORD& uwToRead );
		long											Read( SWORD& swToRead );
		long											Read( ULONG& ulToRead );
		long											Read( SLONG& slToRead );
		long											Read( FLOAT& _rfOutValue );
*/

		/// template static array read function
		template<class Size, class T>
		long											ReadArray		( Size _nbElements, T* _aOutValue );		 

		/// template already allocated dynamic array Write function
		long											ReadByteArray	( ULONG _ulByteCount, void* _aOutValue );

		/// template dynamic array read function
		template<class Size, class T>
		long											ReadAndAllocateDynamicArray	( Size _nbElementss, T*& _raOutValue );


		
		/// Write data to the file, and write the given _strLog into the text log file, if one has been created with this File
		template<class T>
		long											Write			( const char* _strLog, const T& _rtValue );

		/// template static array Write function, and write the given _strLog into the text log file, if one has been created with this File
		template<class Size, class T>
		long											WriteArray		( const char* _strLog, Size _nbElements, T* _aValue );		 

		/// template already allocated dynamic array Write function, and write the given _strLog into the text log file, if one has been created with this File
		long											WriteByteArray	( const char* _strLog, ULONG _ulByteCount, void* _aValue );


		
		/// just checks if a file with the given name exists
		static bool										DoesExist		( const char* _strFilepath );

		/// find the first free filepath matching the requested _strFileName plus "_XXXX" plus the given _extension, and returns it in _strOutFilepath; WARNING : the var _strOutFilepath must be big enough
		static bool										FindFirstFreeName( const char* _strFileName, const char* _strExtension, char* _strOutFilepath );

		/// rename the file from _strOldFilepath to _strNewFilepath
		static bool										Rename			( const char* _strOldFilepath, const char* _strNewFilepath );
/*		
		/// returns a localized filepath if any, i.e, if a MyFile.gui exists and a MyFile__fre.gui exists too, it will return the later
		static const char* 								GetLocalizedFilePath ( const char* _strFilepath );
*/		
		/// gets position in file
		ULONG											GetPosition		( void );
		
		/// sets position in file
		bool											SetPosition		( SLONG slPosition, FileSeekMode seekMode );

		/// returns the Nitro SDK file handle - required for compatibility with some functions (such as Actimagine MobiClip lib's)
		HANDLE&											GetHandle		( void ) { return mfsFile;}

		/// Get the last write time
		void											GetLastWriteTime( SystemTime& _rOutLastWriteTime ) const ;

		/// Compare the given SystemTime, and return >0 (_rTime1 > _rTime2), 0 (_rTime1 == _rTime2), or <0 (_rTime1 < _rTime2)
		static SWORD									CompareTime		( const SystemTime& _rTime1, const SystemTime& _rTime2 );
	private:
		/// forbids copy
		BaseFile( const BaseFile<ErrorPolicy>& otherBaseFile )					{ }
		/// forbids copy
		BaseFile& operator=( const BaseFile<ErrorPolicy> &otherBaseFile )		{ }

		HANDLE											mfsFile;		///< file handle
		HANDLE											mfsWriteLogFile;///< write log file handle
		bool											mbIsOpen;		///< is the file open?
		bool											mbWrite;		///< is this file for writing 
		ULONG											mulPosition;	///< Position of the pointer in the file
	};

#ifdef _DEBUG
	typedef BaseFile< WarningPolicy > File;
#else
	typedef BaseFile<> File;
#endif

	///////////////////////////////////////////////////////////////////////////////////////////////
	// default constructor
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	BaseFile<ErrorPolicy>::BaseFile( void ) 
	:	mfsFile			( nullptr )
	,	mfsWriteLogFile	( nullptr )
	,	mbIsOpen		( false )
	,	mbWrite			( false )
	,	mulPosition		( 0 )
	{ 
	}


	///////////////////////////////////////////////////////////////////////////////////////////////
	// constructor with a file name
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	BaseFile<ErrorPolicy>::BaseFile( const char* _strFilepath, bool _bWrite, const char* _strLog ) 
	:	mfsFile			( nullptr )
	,	mfsWriteLogFile	( nullptr )
	,	mbIsOpen		( false )
	,	mbWrite			( _bWrite )
	,	mulPosition		( 0 )
	{
		Open( _strFilepath, _bWrite, _strLog )
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// destructor
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	BaseFile<ErrorPolicy>::~BaseFile( void )
	{ 
		Close();
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// opens a file
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	bool BaseFile<ErrorPolicy>::Open( const char* _strFilepath, bool _bWrite, const char* _strLog )
	{
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( !IsOpen(), "File already open\n" );
		//-----------------------------------------------------

		mbWrite = _bWrite;
	
		DWORD dwDesiredAccess;
		DWORD dwShareMode;
		DWORD dwCreationDisposition;
		DWORD dwFlags;

		if( _bWrite )
		{
			dwDesiredAccess			= GENERIC_WRITE;
			dwShareMode				= 0;
			dwCreationDisposition	= CREATE_ALWAYS;
			dwFlags					= FILE_ATTRIBUTE_NORMAL;
		}
		else
		{ 
			dwDesiredAccess			= GENERIC_READ;
			dwShareMode				= FILE_SHARE_READ;
			dwCreationDisposition	= OPEN_EXISTING;
			dwFlags					= FILE_FLAG_SEQUENTIAL_SCAN;
		}	 


		mfsFile = CreateFile( _strFilepath, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlags, NULL );

		mbIsOpen = INVALID_HANDLE_VALUE != mfsFile;

		if( !mbIsOpen )
		{
			DWORD iError = GetLastError();
			MB_ERROR( !mbIsOpen , "Error on GetFileTime(...) -- code %d\n", iError );

			mbIsOpen = ErrorPolicy::OnError( *this, _strFilepath );
		}

		if( mbIsOpen && _bWrite && _strLog )
		{
			// Open a log file 
			mfsWriteLogFile = CreateFile( _strLog, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlags, NULL );
		}

		
		return mbIsOpen;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// closes file
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	void BaseFile<ErrorPolicy>::Close( void )
	{
		if( mbIsOpen )
		{
			CloseHandle( mfsFile ); 
			mbIsOpen = false;

			if( nullptr != mfsWriteLogFile )
			{
				CloseHandle( mfsWriteLogFile ); 				
				mbWrite = false;
			}
		}
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// gets file length (in bytes)
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	ULONG BaseFile<ErrorPolicy>::GetLength( void )
	{
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open\n" );
		//-----------------------------------------------------
		
		return GetFileSize( mfsFile, NULL );
	}


/*
	///////////////////////////////////////////////////////////////////////////////////////////////
	// reads data
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::Read( UBYTE& ubToRead )
	{
		return FS_ReadFile( &mfsFile, &ubToRead, sizeof(UBYTE) );
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// reads data
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::Read( SBYTE& sbToRead )
	{
		return FS_ReadFile( &mfsFile, &sbToRead, sizeof(SBYTE) );
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// reads data
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::Read( UWORD& uwToRead )
	{
		return FS_ReadFile( &mfsFile, &uwToRead, sizeof(UWORD) );
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// reads data
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::Read( SWORD& swToRead )
	{
		return FS_ReadFile( &mfsFile, &swToRead, sizeof(SWORD) );
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// reads data
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::Read( ULONG& ulToRead )
	{
		return FS_ReadFile( &mfsFile, &ulToRead, sizeof(ULONG) );
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// reads data
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::Read( SLONG& slToRead )
	{
		return FS_ReadFile( &mfsFile, &slToRead, sizeof(SLONG) );
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// reads data
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::Read( FLOAT& _rfOutValue )
	{ 
		long result = FS_ReadFile( &mfsFile, &_rfOutValue, sizeof(FLOAT) );
		 
		return result;
	}
*/
	///////////////////////////////////////////////////////////////////////////////////////////////
	// default constructor
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	template<class T>
	long BaseFile<ErrorPolicy>::Read( T& _rtOutValue )
	{
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open\n" );
		//-----------------------------------------------------

		DWORD dwBytesRead;

		bool bReadSuccess = ( TRUE == ReadFile( mfsFile, & _rtOutValue, (SLONG)sizeof(T), & dwBytesRead, NULL ) );
		mulPosition += dwBytesRead;

		//------------------------------------------
		// post condition
		MB_ASSERT( bReadSuccess , "Error reading the file\n" );
		//------------------------------------------

		return dwBytesRead;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// template dynamic array read function
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	template<class Size, class T>
	long BaseFile<ErrorPolicy>::ReadAndAllocateDynamicArray( Size _nbElements, T*& _raOutValues )
	{	
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open\n" );
		//-----------------------------------------------------

		SAFE_DELETE_ARRAY( _raOutValues );

		_raOutValues = new T[ _nbElements ];

		//------------------------------------------
		// post condition
		MB_ASSERT_NOT_NULL( _raOutValues , "Unable to allocate memory, go to : File::ReadAndAllocateDynamicArray" );
		//------------------------------------------

		return ReadArray( _nbElements, _raOutValues );
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// template static array read function
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	template<class Size, class T>
	long BaseFile<ErrorPolicy>::ReadArray( Size _nbElements, T* _aOutValues )
	{		
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open\n" );
		//-----------------------------------------------------

		DWORD dwBytesRead;
 
		bool bReadSuccess = ( TRUE == ReadFile( mfsFile, _aOutValues, (SLONG)( sizeof(T) * _nbElements ), & dwBytesRead, NULL ) );
		mulPosition += dwBytesRead;

		//------------------------------------------
		// post condition
		MB_ASSERT( bReadSuccess , "Error reading the file\n" );
		//------------------------------------------

		return dwBytesRead;
	}
 

	///////////////////////////////////////////////////////////////////////////////////////////////
	/// template dynamic array read function
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::ReadByteArray( ULONG _ulByteCount, void* _aOutValues )
	{
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open\n" );
		//-----------------------------------------------------

		DWORD dwBytesRead;
 
		
		bool bReadSuccess = ( TRUE == ReadFile( mfsFile, _aOutValues, (SLONG)( sizeof(UBYTE) * _ulByteCount ), & dwBytesRead, NULL ) );
		mulPosition += dwBytesRead;

		//------------------------------------------
		// post condition
		MB_ASSERT( bReadSuccess , "Error reading the file\n" );
		//------------------------------------------

		return dwBytesRead; 
	}
	 
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Write data to the file, and write the given _strLog into the text log file, if one has been created with this File
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	template<class T>
	long BaseFile<ErrorPolicy>::Write( const char* _strLog, const T& _rtValue )
	{
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open\n" );
		//-----------------------------------------------------

		DWORD dwBytesWritten;

		bool bSuccess = ( TRUE == WriteFile( mfsFile, & _rtValue, (SLONG)sizeof(T), & dwBytesWritten, NULL ) );
		mulPosition += dwBytesWritten;

		if( mfsWriteLogFile && _strLog )
		{
			// Do not check anything, it WILL work :)
			WriteFile( mfsWriteLogFile, _strLog, strlen(_strLog), & dwBytesWritten, NULL );

			//char data[32];
			//sprintf(data, " %f\n", _rtValue );

			//WriteFile( mfsWriteLogFile, data, strlen(data), & dwBytesWritten, NULL );
		}

		//------------------------------------------
		// post condition
		MB_ASSERT( bSuccess , "Error writing the file\n" );
		//------------------------------------------

		return dwBytesWritten;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	// 
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	template<class Size, class T>
	long BaseFile<ErrorPolicy>::WriteArray( const char* _strLog, Size _nbElements, T* _aValues )
	{		
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open\n" );
		//-----------------------------------------------------

		DWORD dwBytesWritten;
 
		bool bSuccess = ( TRUE == WriteFile( mfsFile, _aValues, (SLONG)( sizeof(T) * _nbElements ), & dwBytesWritten, NULL ) );
		mulPosition += dwBytesWritten;

		if( mfsWriteLogFile && _strLog )
		{
			// Do not check anything, it WILL work :)
			WriteFile( mfsWriteLogFile, _strLog, strlen(_strLog), & dwBytesWritten, NULL );			

			// TODO : log the values
			//WriteFile( mfsWriteLogFile, "\n", 1, & dwBytesWritten, NULL );
		}
		//------------------------------------------
		// post condition
		MB_ASSERT( bSuccess , "Error writing the file\n" );
		//------------------------------------------

		return dwBytesWritten;
	}
 

	///////////////////////////////////////////////////////////////////////////////////////////////
	/// 
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	long BaseFile<ErrorPolicy>::WriteByteArray( const char* _strLog, ULONG _ulByteCount, void* _aValues )
	{
		//-----------------------------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open\n" );
		//-----------------------------------------------------

		DWORD dwBytesWritten; 
		
		bool bSuccess = ( TRUE == WriteFile( mfsFile, _aValues, (SLONG)( sizeof(UBYTE) * _ulByteCount ), & dwBytesWritten, NULL ) );
		mulPosition += dwBytesWritten;

		if( mfsWriteLogFile && _strLog )
		{
			// Do not check anything, it WILL work :)
			WriteFile( mfsWriteLogFile, _strLog, strlen(_strLog), & dwBytesWritten, NULL );

			// TODO : log the values
			//WriteFile( mfsWriteLogFile, "\n", 1, & dwBytesWritten, NULL );
		}
		//------------------------------------------
		// post condition
		MB_ASSERT( bSuccess , "Error writing the file\n" );
		//------------------------------------------

		return dwBytesWritten; 
	}
	

	///////////////////////////////////////////////////////////////////////////////////////////////
	// just checks if a file with the given name exists
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	bool BaseFile<ErrorPolicy>::DoesExist( const char* _strFilepath )
	{
		File file;
		
		bool bOpened = file.Open( _strFilepath );
		
		if( bOpened )
		{
			file.Close();
		}
		
		return bOpened;
	}
	

	///////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	bool BaseFile<ErrorPolicy>::FindFirstFreeName( const char* _strFileName, const char* _strExtension, char* _strOutFilepath )
	{	 
		// find a free name for the backup 
		for( int i = 0; i < 9999; i++ )
		{        
			// build the strFilename        
			sprintf( _strOutFilepath, "%s_%.4d.%s", _strFileName, i , _strExtension );

			if( ! File::DoesExist( _strOutFilepath ) )
			{
				return true;
			}
		} 
		
		_strOutFilepath[0] = 0;
		return false;
	}
	

	///////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	bool BaseFile<ErrorPolicy>::Rename( const char* _strOldFilepath, const char* _strNewFilepath )
	{	
		// returns 0 on success
		return 0 == std::rename( _strOldFilepath, _strNewFilepath );
	}

/*
	///////////////////////////////////////////////////////////////////////////////////////////////
	// returns a localized filepath if any, i.e, if a MyFile.gui exists and a MyFile__fre.gui exists too, it will return the later
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	const char* BaseFile<ErrorPolicy>::GetLocalizedFilePath ( const char* strFilepath )
	{		
		OSOwnerInfo info;		
		OS_GetOwnerInfo( &info );
		
		String strLocalizedTag = "__" ;
		strLocalizedTag += Toolbox::GetLanguageCodeString( info.language );
		
		 
		String strLocalizedFilePath ( strFilepath );
		String::size_type posExtensionStart = strLocalizedFilePath.find( ".", 0 );
		
		MB_ASSERT( String::npos != posExtensionStart, "ERROR : unable to find an extension in this filepath  %s\n", strFilepath );
		
		strLocalizedFilePath.insert( posExtensionStart, strLocalizedTag );
		
		if( File::FileExist( strLocalizedFilePath.c_str() ))
		{
#ifndef __FINALROM
			LOG("/!\\ Using localized file '%s' instead of the generic one '%s'\n", strLocalizedFilePath.c_str(), strFilepath );
#endif		
		
			// return localized filepath
			return strLocalizedFilePath.c_str();
		}
		else
		{
			// return the original parameter unmodified 
			return strFilepath;
		}
	}
*/
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// gets position in file
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	ULONG BaseFile<ErrorPolicy>::GetPosition( void )
	{
		//--------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open!\n" );
		//--------------------------------

		return mulPosition;
	}
	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// sets position in file
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	bool BaseFile<ErrorPolicy>::SetPosition( SLONG _slPosition, FileSeekMode _seekMode )
	{
		//--------------------------------
		// precondition
		MB_ASSERT( IsOpen(), "File not open!\n" );
		//--------------------------------

		switch( _seekMode )
		{
		case MB_SEEK_SET:
			mulPosition = _slPosition;
		break;
		case MB_SEEK_CUR:
			mulPosition += _slPosition;
		break;
		case MB_SEEK_END:
			mulPosition = GetLength() + _slPosition;
		break;
		default:
			MB_ASSERT( false, "Unknown seek mode\n" );
		break;
		}
 
		return INVALID_SET_FILE_POINTER  != SetFilePointer( mfsFile, _slPosition, 0, _seekMode ); 
	}

	///////////////////////////////////////////////////////////////////////////////////////////////
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	void BaseFile<ErrorPolicy>::GetLastWriteTime( SystemTime& _rOutLastWriteTime ) const
	{
		BOOL success;

		FILETIME filetimeCreation;
		FILETIME filetimeLastAccess;
		FILETIME filetimeLastWrite;
		success = GetFileTime( mfsFile, &filetimeCreation, &filetimeLastAccess, &filetimeLastWrite);
		MB_ASSERT( 0 != success , "Error on GetFileTime(...) -- code %d\n", GetLastError() );
		
		SystemTime systemtimeCreation;
		success = FileTimeToSystemTime( &filetimeCreation, & systemtimeCreation );
		MB_ASSERT( 0 != success , "Error on FileTimeToSystemTime(...) -- code %d\n", GetLastError() );
 
		success = FileTimeToSystemTime( &filetimeLastWrite, & _rOutLastWriteTime );
		MB_ASSERT( 0 != success , "Error on FileTimeToSystemTime(...) -- code %d\n", GetLastError() );

		if( 0 < CompareTime( systemtimeCreation, _rOutLastWriteTime ) )
		{
			_rOutLastWriteTime = systemtimeCreation;
		} 
	}

	
	///////////////////////////////////////////////////////////////////////////////////////////////
	// Compare the given SystemTime, and return >0 (_rTime1 > _rTime2), 0 (_rTime1 == _rTime2), or <0 (_rTime1 < _rTime2)
	///////////////////////////////////////////////////////////////////////////////////////////////
	template<class ErrorPolicy>
	SWORD BaseFile<ErrorPolicy>::CompareTime( const SystemTime& _rTime1, const SystemTime& _rTime2 )
	{	 		
		SWORD swDeltaYear			= _rTime1.wYear		- _rTime2.wYear;
		SWORD swDeltaMonth			= _rTime1.wMonth	- _rTime2.wMonth;
		SWORD swDeltaDay			= _rTime1.wDay		- _rTime2.wDay; 
		SWORD swDeltaHour			= _rTime1.wHour		- _rTime2.wHour;
		SWORD swDeltaMinute			= _rTime1.wMinute	- _rTime2.wMinute;
		SWORD swDeltaSecond			= _rTime1.wSecond	- _rTime2.wSecond;
		SWORD swDeltaMilliseconds	= _rTime1.wMilliseconds - _rTime2.wMilliseconds;
		
		if( 0 == swDeltaYear )
		{
			if( 0 == swDeltaMonth )
			{ 
				if( 0 == swDeltaDay )
				{ 
					if( 0 == swDeltaHour )
					{ 
						if( 0 == swDeltaMinute )
						{ 
							if( 0 == swDeltaSecond )
							{ 
								if( 0 == swDeltaMilliseconds )
								{
									return 0;
								}
								else
								{
									return swDeltaMilliseconds;
								}
							}
							else
							{
								return swDeltaSecond;
							}	
						}
						else
						{
							return swDeltaMinute;
						}	
					}
					else
					{
						return swDeltaHour;
					}
				}
				else
				{
					return swDeltaDay;
				}
			}
			else
			{
				return swDeltaMonth;
			}	
		}
		else
		{
			return swDeltaYear;
		} 
	}
}
